package com.zhi.syc.data.util

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.ImageFormat
import android.graphics.Point
import android.hardware.Sensor
import android.hardware.SensorManager
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import android.os.Build
import android.telephony.CellInfoCdma
import android.telephony.CellInfoGsm
import android.telephony.CellInfoLte
import android.telephony.CellInfoWcdma
import android.telephony.TelephonyManager
import android.view.WindowManager
import org.json.JSONArray
import org.json.JSONObject
import java.io.BufferedReader
import java.io.File
import java.io.InputStreamReader
import java.util.*

object ASHardwareUtil {

    fun getSensorList(context: Context): String {
        val jsonArray = JSONArray()
        try {
            val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
            val sensors = sensorManager.getSensorList(Sensor.TYPE_ALL)
            for (sensor in sensors) {
                val jsonObject = JSONObject().apply {
                    put("type", sensor.type.toString())
                    put("name", sensor.name.safe())
                    put("version", sensor.version.toString())
                    put("maxRange", sensor.maximumRange.toString().safe())
                    put("vendor", sensor.vendor.safe())
                    put("minDelay", sensor.minDelay.toString().safe())
                    put("power", sensor.power.toString().safe())
                    put("resolution", sensor.resolution.toString().safe())
                }
                jsonArray.put(jsonObject)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return jsonArray.toString()
    }

    private fun checkRootMethod1(): Boolean {
        val buildTags = Build.TAGS
        return buildTags != null && buildTags.contains("test-keys")
    }

    private fun checkRootMethod2(): Boolean {
        val paths = arrayOf(
            "/system/app/Superuser.apk",
            "/sbin/su",
            "/system/bin/su",
            "/system/xbin/su",
            "/data/local/xbin/su",
            "/data/local/bin/su",
            "/system/sd/xbin/su",
            "/system/bin/failsafe/su",
            "/data/local/su"
        )
        return paths.any { File(it).exists() }
    }

    private fun checkRootMethod3(): Boolean {
        var process: Process? = null
        return try {
            process = Runtime.getRuntime().exec(arrayOf("/system/xbin/which", "su"))
            val reader = BufferedReader(InputStreamReader(process.inputStream))
            reader.readLine() != null
        } catch (t: Throwable) {
            false
        } finally {
            process?.destroy()
        }
    }

    fun isDeviceRooted(): Boolean {
        return checkRootMethod1() || checkRootMethod2() || checkRootMethod3()
    }

    fun getIsRoot(): String {
        return if (isDeviceRooted()) "YES" else "NO"
    }

    fun isExecutable(filePath: String): Boolean {
        var process: Process? = null
        return try {
            process = Runtime.getRuntime().exec("ls -l $filePath")
            val reader = BufferedReader(InputStreamReader(process.inputStream))
            val str = reader.readLine()
            str != null && str.length >= 4 && (str[3] == 's' || str[3] == 'x')
        } catch (e: Exception) {
            e.printStackTrace()
            false
        } finally {
            process?.destroy()
        }
    }

    fun getKeyboard(context: Context): String {
        return try {
            val config = context.resources.configuration
            config.keyboard.toString().safe()
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }

    fun getIsSimulator(): String {
        val isMatch = (
                Build.BRAND.startsWith("generic") ||
                        Build.FINGERPRINT.startsWith("generic") ||
                        Build.FINGERPRINT.startsWith("unknown") ||
                        Build.HARDWARE.contains("goldfish") ||
                        Build.HARDWARE.contains("ranchu") ||
                        Build.MODEL.contains("google_sdk") ||
                        Build.MODEL.contains("Emulator") ||
                        Build.MODEL.contains("Android SDK built for x86") ||
                        Build.MANUFACTURER.contains("Genymotion") ||
                        (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) ||
                        "google_sdk" == Build.PRODUCT)

        return if (isMatch) "YES" else "NO"
    }

    fun notHasLightSensorManager(context: Context): Boolean {
        return try {
            val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
            val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
            sensor == null
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    fun isFeatures(): Boolean {
        return (Build.FINGERPRINT.startsWith("generic")
                || Build.FINGERPRINT.toLowerCase(Locale.ROOT).contains("vbox")
                || Build.FINGERPRINT.toLowerCase(Locale.ROOT).contains("test-keys")
                || Build.MODEL.contains("google_sdk")
                || Build.MODEL.contains("Emulator")
                || Build.MODEL.contains("Android SDK built for x86")
                || Build.MANUFACTURER.contains("Genymotion")
                || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
                || "google_sdk" == Build.PRODUCT)
    }

    fun checkIsNotRealPhone(): Boolean {
        val cpuInfo = readCpuInfo()
        return cpuInfo.contains("intel") || cpuInfo.contains("amd")
    }

    fun readCpuInfo(): String {
        return try {
            val args = arrayOf("/system/bin/cat", "/proc/cpuinfo")
            val cmd = ProcessBuilder(*args)
            val process = cmd.start()
            val reader = BufferedReader(InputStreamReader(process.inputStream))
            val sb = StringBuilder()
            var readLine: String?
            val mUtf8Char = "UTF-8"
            while (reader.readLine().also { readLine = it } != null) {
                sb.append(readLine)
            }
            reader.close()
            sb.toString().toLowerCase(Locale.ROOT)
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }

    private val knownPipes = arrayOf("/dev/socket/qemud", "/dev/qemu_pipe")

    fun checkPipes(): Boolean {
        return try {
            knownPipes.any { File(it).exists() }
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    @SuppressLint("MissingPermission")
    fun getMobileDbm(context: Context): String {
        val hadPermission =
            context.checkPermissionsGranted(mutableListOf(Manifest.permission.ACCESS_FINE_LOCATION))
        if (!hadPermission) {
            return ""
        }

        var dbmStr = ""
        try {
            val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            val cellInfoList = tm.allCellInfo
            cellInfoList?.forEach { cellInfo ->
                when (cellInfo) {
                    is CellInfoGsm -> {
                        val cellSignalStrengthGsm = cellInfo.cellSignalStrength
                        val dbm = cellSignalStrengthGsm.dbm
                        dbmStr = dbm.toString().safe()
                    }

                    is CellInfoCdma -> {
                        val cellSignalStrengthCdma = cellInfo.cellSignalStrength
                        val dbm = cellSignalStrengthCdma.dbm
                        dbmStr = dbm.toString().safe()
                    }

                    is CellInfoWcdma -> {
                        val cellSignalStrengthWcdma = cellInfo.cellSignalStrength
                        val dbm = cellSignalStrengthWcdma.dbm
                        dbmStr = dbm.toString().safe()
                    }

                    is CellInfoLte -> {
                        val cellSignalStrengthLte = cellInfo.cellSignalStrength
                        val dbm = cellSignalStrengthLte.dbm
                        dbmStr = dbm.toString().safe()
                    }
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return dbmStr
    }

    fun getFrontCameraPixels(context: Context): String {
        val cameraId = hasFrontCamera(context)
        return getCameraPixels(context, cameraId)
    }

    fun getBackCameraPixels(context: Context): String {
        val cameraId = hasBackCamera(context)
        return getCameraPixels(context, cameraId)
    }

    fun hasFrontCamera(context: Context): Int {
        var cid = -1
        val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
        try {
            val cameraIds = cameraManager.cameraIdList
            for (cID in cameraIds) {
                if (cID == CameraCharacteristics.LENS_FACING_BACK.toString()) {
                    cid = cID.toInt()
                    break
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return cid
    }

    fun hasBackCamera(context: Context): Int {
        var cid = -1
        try {
            val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
            val cameraIds = cameraManager.cameraIdList
            for (cID in cameraIds) {
                if (cID == CameraCharacteristics.LENS_FACING_FRONT.toString()) {
                    cid = cID.toInt()
                    break
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return cid
    }

    fun getCameraPixels(context: Context, paramInt: Int): String {
        var pixelValue = "0"
        if (paramInt == -1)
            return pixelValue

        try {
            val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
            val cameraCharacteristics = cameraManager.getCameraCharacteristics(paramInt.toString())
            val streamConfigurationMap =
                cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
            val sizes = streamConfigurationMap?.getOutputSizes(ImageFormat.JPEG)
            if (!sizes.isNullOrEmpty()) {
                val fistSize = sizes[0]
                val gWidth = fistSize.width
                val gHeight = fistSize.height
                val pixels = (gWidth * gHeight / 10000)
                pixelValue = pixels.toString()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return pixelValue
    }

    fun getMaxNumber(paramArray: IntArray): Int {
        var temp = 0
        try {
            if (paramArray.isNotEmpty()) {
                temp = paramArray[0]
                for (j in paramArray) {
                    if (temp < j) {
                        temp = j
                    }
                }
            }
        } catch (e: ArrayIndexOutOfBoundsException) {
            e.printStackTrace()
        }
        return temp
    }

    fun getPhySicalSize(context: Context): String {
        var sizeStr = ""
        try {
            val point = Point()
            val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
            wm.defaultDisplay.getRealSize(point)
            val dm = context.resources.displayMetrics
            val x = Math.pow(point.x / dm.xdpi.toDouble(), 2.0)
            val y = Math.pow(point.y / dm.ydpi.toDouble(), 2.0)
            val screenInches = Math.sqrt(x + y)
            sizeStr = screenInches.toString()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return sizeStr
    }
}
